home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Compilers⁄Interps / GCC-2.3.3r12 / Sources-Apple / talk.c < prev   
Encoding:
C/C++ Source or Header  |  1993-06-23  |  8.7 KB  |  342 lines  |  [TEXT/MPS ]

  1. #include "config.h"
  2.  
  3. #include <Types.h>
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include <strings.h>
  7. #include <stdio.h>
  8. #include <Events.h>
  9. #include <Sound.h>
  10. #include <Resources.h>
  11.  
  12. char *copy_string();
  13.  
  14. #define MAXRULES 100
  15.  
  16. #define MAXARGS 5
  17.  
  18. struct rule {
  19.     char *key;
  20.     char *args[MAXARGS];
  21.     char *soundname;
  22. };
  23.  
  24. struct rule *rules;
  25.  
  26. int talking = 0;
  27.  
  28. int rude = 0;
  29.  
  30. int numrules = 0;
  31.  
  32. char *commentarypath = NULL;
  33.  
  34. /* Implementation of talking compiler features. */
  35.  
  36. init_talk (char *str, char *prog)
  37. {
  38.     int i;
  39.     char *substr = NULL, line[300], *charpos;
  40.     Str255 tmpstr;
  41.     FILE *fp;
  42.  
  43.     talking = 1;
  44.     if (strcmp(str, "talk-rudely") == 0) {
  45.         rude = 1;
  46.     }
  47.     /* Seed the RNG so that we get random choices. */
  48.     srand(TickCount());
  49.     /* Allocate working space. */
  50.     commentarypath = (char *) xmalloc(255);
  51.     rules = (struct rule *) xmalloc(MAXRULES * sizeof(struct rule));
  52.     if (getenv("COMMENTARY")) {
  53.         sprintf(commentarypath, "%s", getenv("COMMENTARY"));
  54.     } else if (getenv("MPW")) {
  55.         sprintf(commentarypath, "%sCommentary:", getenv("MPW"));
  56.     } else {
  57.         sprintf(commentarypath, ":");
  58.     }
  59.     sprintf (tmpstr, " %sSounds", commentarypath);
  60.     tmpstr[0] = strlen (str);
  61.     OpenResFile (tmpstr);
  62.     /* For testing */
  63.     if (str[4] == 'T') {
  64.         substr = str+5;
  65.         talk (substr, "testing");
  66.     }
  67.     /* Try to read a rule file that adds to or replaces the builtin rules. */
  68.     sprintf (tmpstr, "%sRules", commentarypath);
  69.     if ((fp = fopen (tmpstr, "r")) != NULL) {
  70.         while (fgets(line, 300 - 1, fp) != NULL) {
  71.             line[strlen(line)-1] = '\0';  /* should blast all trailing whitespace too */
  72.             /* Interpret '//' as a comment, blast everything following on line. */
  73.             if ((charpos = strchr(line, '/')) != NULL && *(charpos+1) == '/')
  74.               *charpos = '\0';
  75.             /* Very crude parsing. */
  76.             if ((charpos = strrchr(line, ':')) != NULL) {
  77.                 *charpos = '\0';
  78.                 /* (should filter leading/trailing whitespace) */
  79.                 rules[numrules].soundname = copy_string(charpos+1);
  80.                 for (i = 0; i < MAXARGS; ++i) {
  81.                     rules[numrules].args[i] = NULL;
  82.                 }
  83.                 /* Parse the rule into keyword and argument. */
  84.                 if ((charpos = strchr(line, ' ')) != NULL) {
  85.                     *charpos = '\0';
  86.                     rules[numrules].key = copy_string(line);
  87.                     rules[numrules].args[0] = copy_string(charpos+1);
  88.                 } else {
  89.                     rules[numrules].key = copy_string(line);
  90.                 }
  91.                 ++numrules;
  92.                 if (numrules >= MAXRULES) break;
  93.             }
  94.         }
  95.         fclose (fp);
  96.     }
  97.     /* Just to kick things off. */
  98.     comment ("start", prog);
  99. }
  100.  
  101. /* Try to match the given situation and issue a comment on it. */
  102.  
  103. comment(char *str, char *arg1, char *arg2, char *arg3)
  104. {
  105.     int i, j = 0, matched, numchoices, choices[20];
  106.     int jg = 0, matchedgeneric, numgenericchoices, genericchoices[20];
  107.     int commented = 0;
  108.     char *rulearg, buf[255];
  109.  
  110.     if (talking == 0) return;
  111.     if (str == NULL) return;
  112.     for (i = 0; i < numrules; ++i) {
  113.         if (strcmp(str, rules[i].key) == 0) {
  114.             matched = matchedgeneric = 0;
  115.             rulearg = rules[i].args[0];
  116.             if (strcmp(str, "start") == 0
  117.                 || strcmp(str, "finish") == 0) {
  118.                 /* Require an exact match if arg supplied. */
  119.                 if (arg1 != NULL && rulearg != NULL) {
  120.                     if (strcmp(arg1, rulearg) == 0) matched = 1;
  121.                 } else if (rulearg == NULL) {
  122.                     matchedgeneric = 1;
  123.                 }
  124.             } else if (strcmp(str, "include") == 0
  125.                        || strcmp(str, "macro") == 0
  126.                        || strcmp(str, "function") == 0
  127.                        || strcmp(str, "call") == 0
  128.                        || strcmp(str, "error") == 0
  129.                        || strcmp(str, "warning") == 0) {
  130.                 /* Match on a substring. */
  131.                 if (arg1 != NULL && rulearg != NULL) {
  132.                     if (strstr(arg1, rulearg) != NULL) matched = 1;
  133.                 } else if (rulearg == NULL) {
  134.                     matchedgeneric = 1;
  135.                 }
  136.             } else {
  137.                 /* Otherwise always match the rule, indep of any args. */
  138.                 matchedgeneric = 1;
  139.             }
  140.             if (matched && j < 20) choices[j++] = i;
  141.             if (matchedgeneric && jg < 20) genericchoices[jg++] = i;
  142.         }
  143.     }
  144.     numgenericchoices = jg;
  145.     numchoices = j;
  146.     sprintf(buf, "--- Saw %s, arg \"%s\" ---\n",
  147.                 (str ? str : "???"),
  148.                 (arg1 ? arg1 : "???"));
  149.     if (numchoices > 0) {
  150.         for (i = 0; i < numchoices; ++i) {
  151.             j = (rand() >> 8) % numchoices;
  152.             if (talk (rules[choices[j]].soundname, buf)) {
  153.                 break;
  154.             }
  155.         }
  156.     } else if (numgenericchoices > 0) {
  157.         for (i = 0; i < numgenericchoices; ++i) {
  158.             j = (rand() >> 8) % numgenericchoices;
  159.             if (talk (rules[genericchoices[j]].soundname, buf)) {
  160.                 break;
  161.             }
  162.         }
  163.     }
  164. }
  165.  
  166. /* Given a string naming a sound, try to find and play it.  Return true if
  167.    successfully played, false otherwise. */
  168.  
  169. talk (char *str, char *buf)
  170. {
  171.     short refnum = 0, num, i;
  172.     int openedfile = 0, played = 0;
  173.     Handle soundhandle = nil, tmphandle;
  174.     Str255 tmpstr;
  175.     
  176.     if (!talking) return 0;
  177.     if (str == NULL) return 0;
  178.     /* If the string is empty, pretend we succeeded, but without saying anything.
  179.        This is how a rule can disable commentary coming from more general rules. */
  180.     if (strlen(str) == 0) return 1;
  181.     /* First try loading a sound with a matching name that is already visible
  182.        in the resource chain. */
  183.     sprintf (tmpstr, " %s", str);
  184.     tmpstr[0] = strlen (str);
  185.     soundhandle = GetNamedResource ('snd ', tmpstr);
  186.     if (soundhandle == nil) {
  187.         /* Now try looking for a sound file with a matching name, open it,
  188.            and play the first resource (since sound file resource seems to
  189.            have random name/id) */
  190.         sprintf(tmpstr, " %s%s", commentarypath, str);
  191.         tmpstr[0] = strlen (tmpstr+1);
  192.         if ((refnum = OpenResFile(tmpstr)) != -1) {
  193.             openedfile = 1;
  194.             /* Look for the first resource in the just-opened file. */
  195.             num = CountResources('snd ');
  196.             for (i = 1; i < num; ++i) {
  197.                 tmphandle = GetIndResource('snd ', i);
  198.                 if (HomeResFile(tmphandle) == refnum) {
  199.                     soundhandle = tmphandle;
  200.                     break;
  201.                 }
  202.             }
  203.         }
  204.     }
  205.     /* Play the sound if it exists. */
  206.     if (soundhandle != nil) {
  207.         /* should bring up a window with this in it */
  208.         fprintf(stderr, "\n%s\n", buf); 
  209.         SndPlay (nil, soundhandle, 0);
  210.         played = 1;
  211.     }
  212.     /* Close any resource files that were opened especially for this call. */
  213.     if (openedfile) {
  214.         CloseResFile(refnum);
  215.     }
  216.     if (!played) fprintf(stderr, "Warning: couldn't play \"%s\"\n", str);
  217.     return played;
  218. }
  219.  
  220. #if 0 /* def DO_SPEECH */
  221.  
  222. /* Lifted from TTESample, not actually used */
  223.  
  224. #include "Speech.h"
  225.  
  226.  
  227. #pragma segment Main
  228. OSErr SpeakTextRange(TEHandle te, short sIndex, short eIndex)
  229. {
  230.     long         i;
  231.     long        len;
  232.     Ptr            textPtr;
  233.     OSErr        err = noErr;
  234.  
  235.     if (!te)                        /* no TERecord to work with */
  236.         return nilHandleErr;
  237.     
  238.     textPtr = *((*te)->hText);        /* get ptr to TERecord text */
  239.     
  240.     len = eIndex - sIndex;            /* total length of text to speak */
  241.     
  242.     if (len <= 0)                    /* nothing to speak */
  243.         return noErr;
  244.     
  245.     if (len > 4095)
  246.         len = 4095;
  247.         
  248.     for (i = 0; i < len; i++)        /* copy over the chars we want to speak */
  249.         gTextBuf[i] = textPtr[sIndex + i];
  250.  
  251.     gTextBufLen = (unsigned short) len;
  252.     
  253.     if (len > 255)
  254.         len = 255;                    /* limit length to Str255 max for now */
  255.         
  256.     for (i = 1; i <= len; i++)        /* copy over the chars we want to speak */
  257.         gSpeechStr[i] = textPtr[sIndex + i - 1];
  258.         
  259.     gSpeechStr[0] = (unsigned char) len;
  260.                             
  261.     if (!gSpeechChan)
  262.         {
  263.         if (voiceSel == 0)
  264.             err = NewSpeechChannel(0, &gSpeechChan);
  265.         else
  266.             err = NewSpeechChannel(&vspec[voiceSel], &gSpeechChan);
  267.  
  268.         if (err != noErr)
  269.             AlertUser(eSpeechManager);        /* some kind of error */
  270.         }
  271.  
  272.     if (err == noErr)
  273.     {
  274.             if (!SpeechBusy())
  275.             {
  276.                 err = SpeakBuffer(gSpeechChan, (Ptr) gTextBuf, gTextBufLen, 0);
  277.                 
  278.                 if (err != noErr)
  279.                     AlertUser(eSpeechManager);        /* some kind of error */
  280.             }
  281.             else
  282.                 SysBeep(10);
  283.     }
  284.  
  285.     return err;
  286. }
  287.  
  288.  
  289.  
  290.  
  291.  
  292. #pragma segment Main
  293. void StartupSpeech( void )
  294. {
  295.     OSErr                err;
  296.     short                voiceCount;
  297.     short                i;
  298.     VoiceDescription    vd;
  299.     MenuHandle            voiceMenu;
  300.     NumVersion            ver = SpeechManagerVersion();
  301.  
  302.     #ifndef forRez
  303.     enum {development=0x20, alpha=0x40, beta=0x60, final=0x80, release=0x80};
  304.     #endif
  305.  
  306.     #define kMgrMajorVersion         1                /* 8-bits */
  307.     #define kMgrMinorVersion         0                /* 4-bits */
  308.     #define kMgrBugFixVersion         0                /* 4-bits */
  309.     #define kMgrDevelopmentStage     alpha            /* 8-bits */
  310.     #define kMgrNonRelVersion        2                /* 8-bits */
  311.     
  312.     #define kSpeechManagerVersion     ((kMgrMajorVersion        << 24)         \
  313.                                     | (kMgrMinorVersion     << 20)         \
  314.                                     | (kMgrBugFixVersion     << 16)         \
  315.                                     | (kMgrDevelopmentStage << 8)          \
  316.                                     | (kMgrNonRelVersion))
  317.                                     
  318.     voiceMenu = GetMHandle (mVoice);
  319.  
  320.     err = CountVoices(&voiceCount);
  321.     if (voiceCount > kMaxVoices-1) voiceCount = kMaxVoices-1;
  322.     for (i = 1; i <= voiceCount; i++)
  323.         {
  324.         err = GetIndVoice(i, &vspec[i]);
  325.         
  326.         if ( true || ((*( unsigned long *) (&ver)) >= kSpeechManagerVersion)) 
  327.         {    // newer versions expect you to pass length in parameter list
  328.             err = GetVoiceDescription(&vspec[i], &vd, sizeof(VoiceDescription));
  329.         }
  330.         else 
  331.         {
  332.             //vd.length = sizeof(VoiceDescription);    // early versions require you to set length field
  333.             //err = GetVoiceDescription(&vspec[i], &vd);
  334.         }
  335.         AppendMenu (voiceMenu, vd.name);
  336.         }
  337.     voiceSel = 0;                        // use Default voice
  338. }
  339.  
  340. #endif /* DO_SPEECH */
  341.  
  342.